home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / KERNEL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-20  |  9.5 KB  |  414 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion */
  2. #include <setjmp.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "proc.h"
  6.  
  7. int Stkchk = 0;
  8. struct proc *Curproc;        /* Currently running process */
  9. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  10. struct proc *Waittab[PHASH];    /* Waiting process list */
  11. struct proc *Susptab;        /* Suspended processes */
  12. struct mbuf *Killq;
  13. static void addproc(),delproc();
  14. static unsigned phash();
  15.  
  16. /* Create a process descriptor for the main function. Must be actually
  17.  * called from the main function!
  18.  */
  19. struct proc *
  20. mainproc(name)
  21. char *name;
  22. {
  23.     register struct proc *pp;
  24.  
  25.     /* Create process descriptor */
  26.     if((pp = (struct proc *)calloc(1,sizeof(struct proc))) == NULLPROC)
  27.         return NULLPROC;
  28.  
  29.     /* Create name */
  30.     pp->name = strdup(name);
  31.  
  32.     pp->stksize = 65535;
  33.  
  34.     /* Make current */
  35.     pp->state = READY;
  36.     Curproc = pp;
  37.  
  38.     return pp;
  39. }
  40. /* Create a new, ready process and return pointer to descriptor.
  41.  * The general registers are not initialized, but optional args are pushed
  42.  * on the stack so they can be seen by a C function.
  43.  */
  44. struct proc *
  45. newproc(name,stksize,pc,iarg,parg)
  46. char *name;        /* Arbitrary user-assigned name string */
  47. unsigned int stksize;    /* Stack size to allocate */
  48. void (*pc)();        /* Initial execution address */
  49. int iarg;        /* Integer argument */
  50. void *parg;        /* Generic pointer argument */
  51. {
  52.     register struct proc *pp;
  53.  
  54.     if(Stkchk)
  55.         chkstk(Curproc);
  56.  
  57.     /* Create process descriptor */
  58.     if((pp = (struct proc *)calloc(1,sizeof(struct proc))) == NULLPROC)
  59.         return NULLPROC;
  60.  
  61.     /* Create name */
  62.     pp->name = strdup(name);
  63.  
  64.     /* Allocate stack */
  65.     pp->stksize = stksize;
  66.     if((pp->stack = malloc(stksize)) == NULLCHAR){
  67.         if(pp->name != NULLCHAR)
  68.             free(pp->name);
  69.         free((char *)pp);
  70.         return NULLPROC;
  71.     }
  72.     /* Initialize stack for high-water check */
  73.     memset(pp->stack,STACKPAT,stksize);
  74.  
  75.     /* Do machine-dependent initialization of stack */
  76.     psetup(pp,iarg,parg,pc);
  77.  
  78.     /* Add to ready process table */
  79.     pp->state = READY;
  80.     addproc(pp);
  81.  
  82.     return pp;
  83. }
  84.  
  85. /* Free resources allocated to specified process. If a process wants to kill
  86.  * itself, the reaper is called to do the dirty work. This avoids some
  87.  * messy situations that would otherwise occur, like freeing your own stack.
  88.  */
  89. void
  90. killproc(pp)
  91. register struct proc *pp;
  92. {
  93.     if(pp == NULLPROC)
  94.         return;
  95.     /* Don't check the stack here! Will cause infinite recursion if
  96.      * called from a stack error
  97.      */
  98.  
  99.     if(pp == Curproc)
  100.         killself();    /* Doesn't return */
  101.  
  102.     /* Close any open sockets */
  103.     freesock(pp);
  104.  
  105.     /* Stop alarm clock in case it's running */
  106.     stop_timer(&pp->alarm);
  107.  
  108.     /* Alert everyone waiting for this proc to die */
  109.     psignal(pp,0);
  110.  
  111.     /* Remove from appropriate table */
  112.     delproc(pp);
  113.  
  114.     /* Free allocated memory resources */
  115.     if(pp->name != NULLCHAR)
  116.         free(pp->name);
  117.     free(pp->stack);
  118.     free((char *)pp);
  119. }
  120. /* Terminate current process by sending a request to the killer process.
  121.  * Automatically called when a process function returns. Does not return.
  122.  */
  123. void
  124. killself()
  125. {
  126.     register struct mbuf *bp;
  127.  
  128.     if(Curproc != NULLPROC){
  129.         bp = pushdown(NULLBUF,sizeof(Curproc));
  130.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  131.         enqueue(&Killq,bp);
  132.     }
  133.     for(;;)
  134.         pwait(NULLCHAR);    /* Wait to die */
  135. }
  136. /* Process used by processes that want to kill themselves */
  137. void
  138. killer()
  139. {
  140.     struct proc *pp;
  141.     struct mbuf *bp;
  142.  
  143.     for(;;){
  144.         while(Killq == NULLBUF)
  145.             pwait(&Killq);
  146.         bp = dequeue(&Killq);
  147.         pullup(&bp,(char *)&pp,sizeof(pp));
  148.         free_p(bp);
  149.         if(pp != Curproc)    /* We're immortal */
  150.             killproc(pp);
  151.     }                        
  152. }
  153.  
  154. /* Inhibit a process from running */
  155. void
  156. suspend(pp)
  157. struct proc *pp;
  158. {
  159.     if(pp == NULLPROC)
  160.         return;
  161.     if(pp != Curproc)
  162.         delproc(pp);    /* Running process isn't on any list */
  163.     pp->state |= SUSPEND;
  164.     if(pp != Curproc)
  165.         addproc(pp);    /* pwait will do it for us */
  166.     else
  167.         pwait(NULLCHAR);
  168. }
  169. /* Restart suspended process */
  170. void
  171. resume(pp)
  172. struct proc *pp;
  173. {
  174.     if(pp == NULLPROC)
  175.         return;
  176.     delproc(pp);    /* Can't be Curproc! */
  177.     pp->state &= ~SUSPEND;
  178.     addproc(pp);
  179. }
  180.  
  181. /* Wakeup waiting process, regardless of event it's waiting for. The process
  182.  * will see a return value of "val" from its pwait() call.
  183.  */
  184. void
  185. alert(pp,val)
  186. struct proc *pp;
  187. int val;
  188. {
  189.     if(pp == NULLPROC)
  190.         return;
  191.     if((pp->state & WAITING) == 0)
  192.         return;
  193.     if(pp != Curproc)
  194.         delproc(pp);
  195.     pp->state &= ~WAITING;
  196.     pp->retval = val;
  197.     pp->event = 0;
  198.     addproc(pp);
  199. }
  200.  
  201. /* Post a wait on a specified event and give up the CPU until it happens. The
  202.  * null event is special: it means "I don't want to block on an event, but let
  203.  * somebody else run for a while". It can also mean that the present process
  204.  * is terminating; in this case the wait never returns.
  205.  *
  206.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  207.  * arg in an alert() call. Pwait must not be called from interrupt level.
  208.  */
  209. int
  210. pwait(event)
  211. void *event;
  212. {
  213.     struct proc *oldproc;
  214.     char i_state;
  215.  
  216.     i_state = dirps();
  217.  
  218.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  219.         if(Stkchk)
  220.             chkstk(Curproc);
  221.  
  222.         if(event == NULLCHAR){
  223.             /* Special case; just give up the processor.
  224.              *
  225.              * Optimization: if nothing else is ready, just return.
  226.              */
  227.             if(Rdytab == NULLPROC){
  228.                 restore(i_state);
  229.                 return 0;
  230.             }
  231.         } else {
  232.             /* Post a wait for the specified event */
  233.             Curproc->event = event;
  234.             Curproc->state = WAITING;
  235.         }
  236.         addproc(Curproc);
  237.     }
  238.     /* Look for a ready process and run it. If there are none,
  239.      * loop or halt until an interrupt makes something ready.
  240.      */
  241.     while(Rdytab == NULLPROC){
  242.         /* give system back to upper-level multitasker, if any */
  243.         giveup();
  244.     }
  245.     /* Remove first entry from ready list */
  246.     oldproc = Curproc;
  247.     Curproc = Rdytab;
  248.     delproc(Curproc);
  249.  
  250.     /* Now do the context switch.
  251.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  252.      *
  253.      * If the old process has gone away, simply load the new process's
  254.      * environment. Otherwise, save the current process's state. Then if
  255.      * this is still the old process, load the new environment. Since the
  256.      * new task will "think" it's returning from the setjmp() with a return
  257.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  258.      * would otherwise cause an infinite loop.
  259.      */
  260.     if(oldproc != NULLPROC)
  261.         oldproc->i_state = i_state;
  262.     if(oldproc == NULLPROC || setjmp(oldproc->env) == 0){
  263.         /* Load new task context */
  264.         longjmp(Curproc->env,1);
  265.     }
  266.     /* Restore the true interrupt state here, since the state loaded with
  267.      * the longjmp is wrong (it was turned off as we entered pwait()
  268.      */
  269.     restore(Curproc->i_state);
  270.     return Curproc->retval;
  271. }
  272.  
  273. /* Make ready the first 'n' processes waiting for a given event. The ready
  274.  * processes will see a return value of 0 from pwait().  Note that they don't
  275.  * actually get control until we explicitly give up the CPU ourselves through
  276.  * a pwait(). Psignal may be called from interrupt level.
  277.  */
  278. void
  279. psignal(event,n)
  280. void *event;    /* Event to signal */
  281. int n;        /* Max number of processes to wake up */
  282. {
  283.     register struct proc *pp;
  284.     struct proc *pnext;
  285.     int i_state;
  286.  
  287.     if(Stkchk)
  288.         chkstk(Curproc);
  289.  
  290.     /* n = 0 means "signal everybody waiting for this event" */
  291.     if(n == 0)
  292.         n = 65535;
  293.  
  294.     i_state = dirps();
  295.     for(pp = Waittab[phash(event)];n != 0 && pp != NULLPROC;pp = pnext){
  296.         pnext = pp->next;
  297.         if(pp->event == event){
  298.             delproc(pp);
  299.             pp->state &= ~WAITING;
  300.             pp->event = 0;
  301.             pp->retval = 0;
  302.             n--;
  303.             addproc(pp);
  304.         }
  305.     }
  306.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  307.         pnext = pp->next;
  308.         if(pp->event == event){
  309.             delproc(pp);
  310.             pp->state &= ~WAITING;
  311.             pp->event = 0;
  312.             pp->retval = 0;
  313.             addproc(pp);
  314.             n--;
  315.         }
  316.     }
  317.     restore(i_state);
  318. }
  319.  
  320. /* Rename a process */
  321. void
  322. chname(pp,newname)
  323. struct proc *pp;
  324. char *newname;
  325. {
  326.     if(pp->name != NULLCHAR)
  327.         free(pp->name);
  328.     pp->name = strdup(newname);
  329. }
  330. /* Remove a process entry from the appropriate table */
  331. static void
  332. delproc(entry)
  333. register struct proc *entry;    /* Pointer to entry */
  334. {
  335.     int i_state;
  336.  
  337.     if(entry == NULLPROC)
  338.         return;
  339.  
  340.     i_state = dirps();
  341.     if(entry->next != NULLPROC)
  342.         entry->next->prev = entry->prev;
  343.     if(entry->prev != NULLPROC)
  344.         entry->prev->next = entry->next;
  345.     else {
  346.         switch(entry->state){
  347.         case READY:
  348.             Rdytab = entry->next;
  349.             break;
  350.         case WAITING:
  351.             Waittab[phash(entry->event)] = entry->next;
  352.             break;
  353.         case SUSPEND:
  354.         case SUSPEND|WAITING:
  355.             Susptab = entry->next;
  356.             break;
  357.         }
  358.     }
  359.     restore(i_state);
  360. }
  361. /* Append proc entry to end of appropriate list */
  362. static void
  363. addproc(entry)
  364. register struct proc *entry;    /* Pointer to entry */
  365. {
  366.     register struct proc *pp;
  367.     struct proc **head;
  368.     int i_state;
  369.  
  370.     if(entry == NULLPROC)
  371.         return;
  372.  
  373.     i_state = dirps();
  374.     switch(entry->state){
  375.     case READY:
  376.         head = &Rdytab;
  377.         break;
  378.     case WAITING:
  379.         head = &Waittab[phash(entry->event)];
  380.         break;
  381.     case SUSPEND:
  382.     case SUSPEND|WAITING:
  383.         head = &Susptab;
  384.         break;
  385.     }
  386.     entry->next = NULLPROC;
  387.     if(*head == NULLPROC){
  388.         /* Empty list, stick at beginning */
  389.         entry->prev = NULLPROC;
  390.         *head = entry;
  391.     } else {
  392.         /* Find last entry on list */
  393.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  394.             ;
  395.         pp->next = entry;
  396.         entry->prev = pp;
  397.     }
  398.     restore(i_state);
  399. }
  400. static unsigned
  401. phash(event)
  402. void *event;
  403. {
  404.     register char *cp = (char *)&event;
  405.     int i = sizeof(event);
  406.     register unsigned x = 0;
  407.  
  408.     while(i-- != 0)
  409.         x ^= *cp++;
  410.  
  411.     return x % PHASH;
  412. }
  413.  
  414.